﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TryTM
{
    public partial class frmMain : Form
    {
        public List<List<string>> Transaction = new List<List<string>>();// Список списка ключевых слов 
        public List<DefaultClust> ClasterList = new List<DefaultClust>();
        public List<string> FileToCluster=new List<string>();
        public double R;
        

         public class DefaultClust
        {
            public int S = 0;
            public int W = 0;
            public double H = 0;
            public List<int> Tranz = new List<int>();
            public List<string> D = new List<string>();
            public List<int> Occ = new List<int>();
              
        }

         public void LoadInfo()
         {
             FileToCluster.Clear();
             Transaction.Clear();
             foreach (DataRow FileRow in DataTable_FILES.Rows)
             {
                 FileToCluster.Add(FileRow.Field<string>(Class_Table_FILES_Columns.FullPathToFile));
                 var TempTrans = (from Files in DataTable_FILES.AsEnumerable()
                                  from Words in DataTable_WORDS.AsEnumerable()
                                  join KeyWord in DataTable_KeyWords.AsEnumerable()
                                  on new { A = Files.Field<int>(Class_Table_FILES_Columns.ID_FullPathToFile), B = Words.Field<int>(Class_Table_WORDS_Columns.ID_Word) } equals
                                  new { A = KeyWord.Field<int>(Class_Table_KeyWords_Columns.ID_FullPathToFile), B = KeyWord.Field<int>(Class_Table_KeyWords_Columns.ID_Word) }
                                  into SomeData
                                  from DataNya in SomeData
                                  where DataNya.Field<int>(Class_Table_KeyWords_Columns.ID_FullPathToFile) == FileRow.Field<int>(Class_Table_FILES_Columns.ID_FullPathToFile)
                                  select Words.Field<string>(Class_Table_WORDS_Columns.Word)).ToList();
                 Transaction.Add(TempTrans);
             }

             //вот тут загрузка из линку
             //
             
         }

        public void BeginClusteristion()
        {
            ClasterList.Clear();
            LoadInfo();
            CreateCluster();
            return;
        }

        private void CreateCluster()
        {
            ClasterList.Clear();
            for (int i = 0; i < Transaction.Count; i++)
            {
                DefaultClust clust = new DefaultClust();
                double adds = DeltaAddInNew(Transaction[i]);
                int count = ClasterList.Count;
                for (int j = 0; j < ClasterList.Count; j++)
                {
                    double tmp = DeltaAdd(ClasterList[j], Transaction[i]);
                    if (tmp > adds)
                    {
                        adds = tmp;
                        count= j;
                    }
                }
                AddToCluster(Transaction[i], count, i);
            }
            bool isMoved = true;
            while (isMoved)
            {
                isMoved = false;
                for (int i = 0; i < ClasterList.Count; i++)
                {
                    for (int j = 0; j < ClasterList[i].Tranz.Count; j++)
                    {
                        double deltaD = DeltaDel(ClasterList[i], Transaction[ClasterList[i].Tranz[j]]);

                        double adds = DeltaAddInNew(Transaction[ClasterList[i].Tranz[j]]);
                        int numb = ClasterList.Count;
                        for (int k = 0; k < ClasterList.Count; k++)
                        {
                            double tmp = DeltaAdd(ClasterList[k], Transaction[ClasterList[i].Tranz[j]]);
                            if (tmp > adds)
                            {
                                adds = tmp;
                                numb = k;
                            }
                        }
                        if (adds + deltaD > 0 && i != numb)
                        {
                            int ind = ClasterList[i].Tranz[j];
                            DelFromClaster(Transaction[ind], i, ind);
                            AddToCluster(Transaction[ind], numb, ind);
                            isMoved = true;
                        }
                    }
                }
            }
            DelEmpty();
            richTextBox2.Text = "";
            StringBuilder LogCluster=new StringBuilder(500);
            //запись в файл)
            for (int i = 0; i < ClasterList.Count; i++)
            {
                if (LogCluster != null)
                {
                    LogCluster.AppendLine("Создали"+(i+1).ToString()+" кластер ");
                    LogCluster.AppendLine("");

                    foreach (int t in ClasterList[i].Tranz)
                    {
                        var str = FileToCluster[t].ToString();
                        LogCluster.AppendLine(str);
                        LogCluster.AppendLine("");
                        //string st = "";
                        //for (int k = 0; k < Transaction[t].Count; k++)
                        //    st += Transaction[t][k] + " ";
                        //LogCluster.AppendLine(st);
                    }
                    richTextBox2.Text = LogCluster.ToString();
                }
                LogCluster.AppendLine("");
            }
        }

       
        public void AddToCluster(List<string> t, int n, int t_num)
        {
            if (n == ClasterList.Count)
            {
                ClasterList.Add(new DefaultClust());
            }
            for (int i = 0; i < t.Count; i++)
            {
                if (!ClasterList[n].D.Contains(t[i]))
                {
                    ClasterList[n].W += 1;
                    ClasterList[n].D.Add(t[i]);
                    ClasterList[n].Occ.Add(1);
                }
                else
                {
                    int ind = ClasterList[n].D.IndexOf(t[i]);
                    ClasterList[n].Occ[ind] += 1;
                }
            }
            ClasterList[n].S += t.Count;
            ClasterList[n].H = (double)ClasterList[n].S / ClasterList[n].W;
            ClasterList[n].Tranz.Add(t_num);

        }
        public void DelFromClaster(List<string> t, int n, int t_num)
        {
            for (int i = 0; i < t.Count; i++)
            {
                int ind = ClasterList[n].D.IndexOf(t[i]);
                ClasterList[n].Occ[ind] -= 1;
                if (ClasterList[n].Occ[ind] == 0)
                {
                    ClasterList[n].W -= 1;
                    ClasterList[n].D.Remove(t[i]);
                }
            }
            ClasterList[n].S -= t.Count;
            if (ClasterList[n].W != 0)
            {
                ClasterList[n].H = (double)ClasterList[n].S / ClasterList[n].W;
            }
            else
            {
                ClasterList[n].H = 0;
            }
            ClasterList[n].Tranz.Remove(t_num);
        }
        public double DeltaAddInNew(List<string> t)
        {
            return (double)t.Count / System.Math.Exp(t.Count * System.Math.Log(R));
        }

        public double DeltaDel(DefaultClust c, List<string> t)
        {
            int S_new;
            S_new = c.S - t.Count;
            int W_new = c.W;

            for (int i = 0; i < t.Count; i++)
            {
                if (c.Occ[c.D.IndexOf(t[i])] == 1) W_new = W_new - 1;
            }
            return S_new * (c.Tranz.Count - 1) / System.Math.Exp(W_new * System.Math.Log(R)) - c.S * c.Tranz.Count / System.Math.Exp(c.W * System.Math.Log(R));
        }

        public double DeltaAdd(DefaultClust c, List<string> t)
        {
            int S_new;
            S_new = c.S + t.Count;
            int W_new = c.W + t.Count(t1 => !c.D.Contains(t1));

            return S_new * (c.Tranz.Count + 1) / Math.Exp(W_new * Math.Log(R)) - c.S * c.Tranz.Count / Math.Exp(c.W * Math.Log(R));
        }

        public void DelEmpty()
        {
            int i = 0;
            while (i < ClasterList.Count)
            {
                if (ClasterList[i].Tranz.Count == 0)
                {
                    ClasterList.RemoveAt(i);
                }
                else
                {
                    i += 1;
                }
            }
        }

        private void frmMain_Load(object sender, EventArgs e)
        {

        }

    }
}
